home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / UTILITY / CMDED2E6.ARJ / UTL.ASM < prev   
Assembly Source File  |  1992-06-30  |  17KB  |  729 lines

  1. ; UTL.ASM
  2. ; (c) 1989, 1990 Ashok P. Nadkarni
  3. ;
  4. ; General utility functions for CMDEDIT. SMALL model only. Also assume 
  5. ; ES == DS. 
  6. ;
  7.  
  8.     INCLUDE common.inc
  9.     INCLUDE    general.inc
  10.     INCLUDE    ascii.inc
  11.     INCLUDE dos.inc
  12.     INCLUDE buffers.inc
  13.  
  14.     PUBLIC    stre_cmp
  15.     PUBLIC    tolower
  16.     PUBLIC    xlate_lower
  17.     PUBLIC    getargs
  18.     PUBLIC    isalphnum
  19.     PUBLIC    iscntrl
  20.     PUBLIC    isspace
  21.     PUBLIC    isdelim
  22.     PUBLIC    bell
  23.     PUBLIC    push_string
  24.     PUBLIC    push_word
  25.     PUBLIC    skip_nonwhite
  26.     PUBLIC    skip_whitespace
  27.     PUBLIC    skip_nondelim
  28.     PUBLIC    output_newline
  29.     PUBLIC    output_counted_string
  30.     PUBLIC    dosify_line        ; added by wd
  31.     
  32.     EXTRN    silent:BYTE
  33.     EXTRN    lastchar:WORD
  34.     EXTRN    linebuf:BYTE
  35.  
  36.  
  37. CSEG    SEGMENT    PARA PUBLIC 'CODE'
  38.  
  39. DGROUP    GROUP    CSEG
  40.  
  41.     ASSUME    CS:DGROUP,DS:DGROUP,ES:DGROUP,SS:DGROUP
  42.  
  43. ;+
  44. ; FUNCTION : stre_cmp
  45. ;
  46. ;    Does a case-insensitve comparison of two strings of equal length.
  47. ;
  48. ; Parameters:
  49. ;    DS:SI :=    Address of string 1.
  50. ;    ES:DI :=    Address of string 2.
  51. ;    CX    :=    Length.
  52. ;
  53. ; Returns:
  54. ;    If string 1 = string 2, ZF = 1, CF = 0.
  55. ;    If string 1 < string 2, ZF = 0, CF = 1.
  56. ;    If string 1 > string 2, ZF = 0, CF = 0.
  57. ; Registers AX,CX destroyed.
  58. ;-
  59. stre_cmp proc near
  60.     @save    si,di,dx
  61.     dec    si        ;Prime for loop
  62.     dec    di
  63.     xor    ax,ax        ;Clear flags
  64.     jcxz    @stre_cmp_99
  65. @stre_cmp_10:
  66.     cmpsb            ;Point SI,DI to next byte
  67.     mov    al,[si]        ;String 1 byte
  68.     call    near ptr tolower ;al := Uppercase version
  69.     xchg    al,dl        ;Save it.
  70.     mov    al,ES:[di]    ;Ditto for string 2
  71.     call    near ptr tolower ;al := Uppercase version
  72.     cmp    dl,al        ;Compare string 1 with string 2
  73. @stre_cmp_20:
  74.     loope    @stre_cmp_10    ;Keep looping as long as equal
  75. @stre_cmp_99:
  76.     @restore
  77.     ret
  78. stre_cmp endp
  79.  
  80.  
  81. ;+
  82. ; FUNCTION : tolower
  83. ;
  84. ;    Converts the character in AL to lower case if it is a upper case
  85. ;    character, else leaves it unchanged.
  86. ;
  87. ; Parameters:
  88. ;    Al :=    character
  89. ;
  90. ; Returns:
  91. ;    AL :=    lowercase version or unchanged
  92. ;-
  93. tolower    proc near
  94.     cmp    al,'A'
  95.     jb    @tolower_99
  96.     cmp    al,'Z'
  97.     ja    @tolower_99
  98.     add    al,20h
  99. @tolower_99:
  100.     ret
  101. tolower    endp
  102.  
  103.  
  104.  
  105. ;+
  106. ; FUNCTION : xlate_lower
  107. ;
  108. ;    Converts the passed string to lower case.
  109. ;
  110. ; Parameters:
  111. ;    AX :=    length of string
  112. ;    SI :=    address of string
  113. ;
  114. ; Returns:
  115. ;    Nothing.
  116. ;
  117. ; Registers destroyed:
  118. ;    AX,CX
  119. ;-
  120. xlate_lower proc near
  121.     @save    si,di
  122.     mov    di,si
  123.     mov    cx,ax
  124.     jcxz    @xlate_lower_99
  125.  
  126. @xlate_lower_10:
  127.     lodsb
  128.     call    near ptr tolower
  129.     stosb
  130.     loop    @xlate_lower_10
  131.     
  132. @xlate_lower_99:
  133.     @restore
  134.     ret
  135. xlate_lower endp
  136.  
  137.  
  138.  
  139. ;+ FUNCTION : getargs
  140. ;
  141. ;    getargs does one of two functions depending on the value in AX.
  142. ;    If AX = 0, returns count of arguments in the line,
  143. ;    else if AX = n, returns the nth argument.
  144. ;
  145. ;    The argument separators are tab and space. Note that a
  146. ;    carraige return (0Dh) terminates a line even if the byte
  147. ;    count indicates otherwise.  Arguments containing a SPACE or
  148. ;    TAB separator may be specified by enclosing them in a pair of
  149. ;    quotes ("). The quotes do NOT act as argument delimiters. For
  150. ;    example the following line
  151. ;        this"is a single "arg
  152. ;    contains exactly one argument. An unmatched quote causes the
  153. ;    remaining characters in the line to be treated as a single
  154. ;    argument. A quote character can be included as part of an
  155. ;    argument by preceding it with a ESCARG character. An ESCARG preceding
  156. ;    any other character does not have any special meaning.
  157. ;      Note that all other characters including the NUL char (00h)
  158. ;    have no special significance.
  159. ;
  160. ; Parameters:
  161. ;    DS:SI points to the line
  162. ;    AX = argument number n
  163. ;    CX = Length of line
  164. ;    If parameter n != 0,
  165. ;    then BX = address of user buffer where the returned argument is to
  166. ;        be stored. This param need not be present if n is 0.
  167. ;         DX = length of user buffer.
  168. ;
  169. ;
  170. ; Returns:
  171. ;    If parameter n was 0,
  172. ;        return argument count in AX (CF is undefined),
  173. ;    else
  174. ;        Store n'th argument in the buffer pointed to by BX and
  175. ;        return the number of chars in the argument in AX.
  176. ;        The returned argument has quotes and ESCARGes stripped
  177. ;        out where appropriate. If the buffer is too small, CF
  178. ;        is set to 1, else it is 0. In this case the user buffer
  179. ;        contents are undefined.
  180. ;    BX is explicitly unchanged.
  181. ;
  182. ; Registers CX,DX are destroyed.
  183. ;-
  184. getargs    proc    near
  185. ESCARG    EQU    PERCENT
  186.     @save    si,di
  187.     push    bp
  188.     mov    bp,sp
  189.     sub    sp,2
  190. userbuf_len EQU <word ptr [bp-2]>
  191.     mov    di,ax        ;save argument number
  192.  
  193.     xor    ax,ax        ;al will hold char, ah will hold state
  194.     mov    userbuf_len,dx    ;Save size of user buffer
  195.     xor    dx,dx        ;dx counts arguments
  196.                 ;CX = line length
  197.     or    cx,cx        ;Check if CX is 0 (jump too far for jcxz)
  198.     jne    @getargs_2
  199.     jmp    @getargs_99    ;0 length, jump around ajnup
  200. @getargs_2:
  201. ;    At the start of this loop, the following hold :
  202. ;    (1) CX >= 1. CX holds count of remaining characters.
  203. ;    (2) ah holds the current "state" with the following encoding -
  204. ;        When Bit 1 is 0, bit 0=0 indicates we're outside an argument
  205. ;        and bit0=1 indicates we are inside an arg.
  206. ;        When Bit 1 is 1, we are inside a quoted argument. In this
  207. ;        case, bit 0 "remembers" the state we were in before the
  208. ;        quotes so that it can be restored upon reaching the closing
  209. ;        quotes.
  210. ;        Bit 2 remembers if prev char was a ESCARG (=1) or not (=0)
  211. ;        Bit 3 = 1 indicates this argument is to be copied into the
  212. ;              user buffer
  213.  
  214. in_arg        equ    01h
  215. in_quote     equ    02h
  216. saw_ESCARG    equ    04h
  217.     lodsb                ;Get next char
  218.     cmp    al,CR            ;If carraige-return
  219.     je    @getargs_50        ;  then terminate processing.
  220.     call    near ptr isspace    ;Check if space or tab
  221.     jne    @getargs_10        ;No, jump
  222. ;    Process separator
  223.     and    ah,NOT saw_ESCARG ;Remember char is not a ESCARG
  224.     test    ah,in_quote    ;Are we inside quotes ?
  225.     jnz    @getargs_49        ;If so go onto next char
  226.     and    ah,NOT in_arg    ;else reset the inside arg flag
  227.     jmp    short @getargs_49    ;and go onto next char
  228.  
  229.  
  230. @getargs_10:            ;Not a separator
  231.     test    ah,in_arg OR in_quote ;Were we inside an arg or quoted arg ?
  232.     jnz    @getargs_11        ;Yes, then skip the increment
  233.                 ;else entering an arg, so
  234.     inc    dx        ;    increment arg count
  235.     or    di,di        ;    If function is return arg count
  236.     je    @getargs_11        ;    then go on
  237.     cmp    di,dx        ;    else check if this is the arg we want
  238.     jne    @getargs_11        ;    Nope, keep on
  239.                 ;    Yep, this be the one
  240.     mov    di,bx        ;di = destination buf, ES assumed = DS
  241.     xor    dx,dx        ;Zero the character count
  242.     jmp    short @getargs_80    ;Go to the copy loop
  243. @getargs_11:
  244.     cmp    al,QUOTE    ;Is this a quote ?
  245.     jne    @getargs_15        ;No, normal processing
  246.     test    ah,saw_ESCARG    ;Found quote, was prev char a ESCARG ?
  247.     jnz    @getargs_15        ;Yes, normal processing
  248.     xor    ah,in_quote    ;else toggle the quote flag
  249.     jmp    short @getargs_49    ;go onto next char
  250. @getargs_15:            ;Normal processing
  251.     and    ah,NOT saw_ESCARG ;assume char is not a ESCARG
  252.     cmp    al,ESCARG    ;Is this a ESCARG ?
  253.     jnz    @getargs_20        ;No
  254.     or    ah,saw_ESCARG    ;Set ESCARG flag
  255. @getargs_20:
  256.     test    ah,in_quote    ;Are we inside quotes ?
  257.     jnz    @getargs_49        ;If so go onto next char
  258.     or    ah,in_arg    ;else set the inside arg flag
  259.  
  260. @getargs_49:
  261.     loop    @getargs_2        ;Go onto next char if any
  262.  
  263. @getargs_50:            ;Finished with the line
  264.     or    di,di        ;Were we supposed to return an argument ?
  265.     je    @getargs_99        ;No, so go on
  266.     xor    dx,dx        ;Yes, but arg num was > number of args
  267.                 ; so return a 0 count
  268.     jmp    short @getargs_99    ;Skip over copy arg section
  269.  
  270.  
  271.  
  272. ;Copy argument loop begins.
  273.  
  274. @getargs_70:
  275.     lodsb                ;Get next char
  276.     cmp    al,CR            ;If carraige-return
  277.     je    @getargs_99        ;  then terminate processing.
  278.  
  279.     call    near ptr isspace    ;Check if space or tab
  280.     jne    @getargs_80        ;No, jump
  281.  
  282. ;    Process separator
  283.     test    ah,in_quote    ;Are we inside quotes ?
  284.     jz    @getargs_99        ;No, terminate processing
  285.     jmp    short @getargs_85    ;Treat like any other char
  286.  
  287. @getargs_80:            ;Not a separator
  288.     ;At this point CX = num of bytes remaining in the line including the
  289.     ;one in AL.
  290.  
  291.     cmp    al,QUOTE    ;Is this a quote ?
  292.     jne    @getargs_85        ;No, normal processing
  293.     test    ah,saw_ESCARG    ;Found quote, was prev char a ESCARG ?
  294.     jnz    @getargs_84        ;Yes, jump
  295.     xor    ah,in_quote    ;else toggle the quote flag
  296.     jmp    short @getargs_89    ;go onto next char
  297.  
  298. @getargs_84:            ;Found a \" combination
  299.     dec    di        ;Previous \ shouldn't have been written
  300.     dec    dx        ;or counted.
  301.                 ;fall thru for normal processing
  302.  
  303. @getargs_85:            ;Normal processing
  304.     sub    userbuf_len,1    ;Decrement space remaining in buffer. Do
  305. ;                 NOT use DEC here since CF needs to be set
  306.     jb    @getargs_100    ;No more space, exit with CF set
  307.     stosb            ;Store the char
  308.     inc    dx        ;and incr count
  309.  
  310.     and    ah,NOT saw_ESCARG ;assume char is not a ESCARG
  311.     cmp    al,ESCARG    ;Is this a ESCARG ?
  312.     jnz    @getargs_89    ;No
  313.     or    ah,saw_ESCARG    ;Set ESCARG flag
  314.  
  315. @getargs_89:
  316.     loop    @getargs_70    ;Go onto next char if any
  317.  
  318. @getargs_99:
  319.     xchg    ax,dx        ;AX<-arg count or num chars in returned arg
  320.     clc            ;Clear CF for no error
  321. @getargs_100:
  322.     mov    sp,bp
  323.     pop    bp
  324.     @restore
  325.     ret
  326. getargs    endp
  327.  
  328.  
  329.  
  330.  
  331. ;+
  332. ; FUNCTION : isalphnum
  333. ;
  334. ;    Test if the character is alphanumeric.
  335. ;
  336. ; Parameters:
  337. ;    AL    = character
  338. ;
  339. ; Returns:
  340. ;    CF    = 0 if alphanumeric
  341. ;          1 if not
  342. ; Register(s) destroyed:
  343. ;-
  344. isalphnum proc near
  345.     cmp    al,'0'
  346.     jc    @isalphnum_99        ;Not alphanumeric
  347.     cmp    al,'9'+1
  348.     cmc
  349.     jnc    @isalphnum_99        ;Number
  350.     cmp    al,'A'
  351.     jc    @isalphnum_99        ;Not alphanumeric
  352.     cmp    al,'Z'+1
  353.     cmc
  354.     jnc    @isalphnum_99        ;Uppercase letter
  355.     cmp    al,'a'
  356.     jc    @isalphnum_99        ;Not alphanumeric
  357.     cmp    al,'z'+1
  358.     cmc
  359. @isalphnum_99:
  360.     ret
  361. isalphnum endp
  362.  
  363.  
  364.  
  365. ;+
  366. ; FUNCTION : iscntrl
  367. ;
  368. ;    Check if control character and DEL (00h-1Fh and 0FFh).
  369. ;
  370. ; Parameters:
  371. ;    AL    = character to be checked
  372. ;
  373. ; Returns:
  374. ;    CF    = 0 if AL is a control character or DEL
  375. ;          1 not a control char or DEL
  376. ; Register(s) destroyed:
  377. ;-
  378. iscntrl    proc    near
  379.     cmp    al,DEL
  380.     jne    @iscntrl_99
  381.     cmp    al,' '
  382.     cmc
  383. @iscntrl_99:
  384.     ret
  385. iscntrl    endp
  386.  
  387.  
  388.  
  389. ;+
  390. ; FUNCTION : isspace
  391. ;
  392. ;    Check if a character is a SPACE or a TAB
  393. ;
  394. ; Parameters:
  395. ;    AL    = character to check
  396. ;
  397. ; Returns:
  398. ;    ZF    = 1 if AL is a space or a tab
  399. ;          0 otherwise
  400. ; Register(s) destroyed:
  401. ;
  402. ;-
  403. isspace    proc    near
  404.     cmp    al,TAB
  405.     je    @isspace_99
  406.     cmp    al,SPACE
  407. @isspace_99:
  408.     ret
  409. isspace    endp
  410.  
  411.  
  412.  
  413. ;+
  414. ; FUNCTION : isdelim
  415. ;
  416. ;    Check if a character is an MSDOS delimiter.
  417. ;
  418. ; Parameters:
  419. ;    AL    = character to check
  420. ;
  421. ; Returns:
  422. ;    ZF    = 1 if AL is a delimiter
  423. ;          0 otherwise
  424. ; Register(s) destroyed:
  425. ;
  426. ;-
  427. isdelim    proc    near
  428.     call    near ptr isspace    ;Check if space or tab
  429.     je    @isdelim_99        ;Yes, go return
  430.     cmp    al,'/'
  431.     je    @isdelim_99        ;Yes, go return
  432.     cmp    al,'|'
  433.     je    @isdelim_99        ;Yes, go return
  434.     cmp    al,'<'
  435.     je    @isdelim_99        ;Yes, go return
  436.     cmp    al,'>'
  437. @isdelim_99:
  438.     ret
  439. isdelim    endp
  440.  
  441.  
  442.  
  443. ;+
  444. ; FUNCTION : skip_whitespace
  445. ;
  446. ;    Searches for the next non-whitespace character in a given string.
  447. ;
  448. ; Parameters:
  449. ;    SI    -> pointer to string
  450. ;    CX    == num chars in the string
  451. ;
  452. ; Returns:
  453. ;    CF    = 1 if end-of string reached else 0
  454. ;    SI    ->next non-whitespace character or end-of-string
  455. ;    CX    <-num remaining characters including one pointed to by SI
  456. ;
  457. ; Register(s) destroyed:
  458. ;    AX
  459. ;-
  460. skip_whitespace proc near
  461.     jcxz    @skip_whitespace_98        ;Empty string
  462. @skip_whitespace_10:
  463.     lodsb                    ;AL<-next char
  464.     call    near ptr isspace        ;Whitespace character ?
  465.     loope    @skip_whitespace_10        ;Repeat until
  466. ;                         non-whitespace or string ends
  467.     je    @skip_whitespace_98        ;End-of-string
  468. ; Non-whitespace char found
  469.     dec    si                ;SI->non-whitespace char
  470.     inc    cx                ;CX<-remaining number of bytes
  471.     clc                    ;CF<-0 (char found)
  472.     jmp    short @skip_whitespace_99
  473.  
  474. @skip_whitespace_98:
  475. ; End of string reached.
  476.     stc                    ;Set CF
  477.  
  478. @skip_whitespace_99:
  479.     ret
  480. skip_whitespace endp
  481.  
  482.  
  483.  
  484.  
  485. ;+ FUNCTION : skip_nonwhite, skip_nondelim
  486. ;
  487. ;    Searches for the next whitespace character / delimiter in a given
  488. ;    string.
  489. ;
  490. ; Parameters:
  491. ;    SI    -> pointer to string
  492. ;    CX    == num chars in the string
  493. ;
  494. ; Returns:
  495. ;    CF    = 1 if end-of string reached else 0
  496. ;    SI    ->next whitespace character or end-of-string
  497. ;    CX    <-num remaining characters including one pointed to by SI
  498. ;
  499. ; Register(s) destroyed:
  500. ;    AX
  501. ;-
  502. skip_non proc near
  503. skip_nonwhite LABEL near
  504.     push    dx
  505.     mov    dx,offset DGROUP:isspace
  506.     jmp    short @skip_non    
  507.  
  508. skip_nondelim LABEL near
  509.     push    dx
  510.     mov    dx,offset DGROUP:isdelim
  511. @skip_non:
  512.     jcxz    @skip_non_98            ;Empty string
  513. @skip_non_10:
  514.     lodsb                    ;AL<-next char
  515.     call    dx                ;nonwhite / delimiter
  516. ;                         character ? 
  517.     loopne    @skip_non_10            ;Repeat until
  518. ;                         whitespace or string ends
  519.     jne    @skip_non_98            ;End-of-string
  520. ; whitespace char found
  521.     dec    si                ;SI->whitespace char
  522.     inc    cx                ;CX<-remaining number of bytes
  523.     clc                    ;CF<-0 (char found)
  524.     jmp    short @skip_non_99
  525.  
  526. @skip_non_98:
  527. ; End of string reached.
  528.     stc                    ;Set CF
  529.  
  530. @skip_non_99:
  531.     pop    dx
  532.     ret
  533. skip_non endp
  534.  
  535.  
  536.  
  537.  
  538.  
  539.  
  540. ;+
  541. ; FUNCTION : push_word
  542. ;
  543. ;    Looks for the next word (delimited by whitespace) and pushes it
  544. ;    onto the specified string stack.
  545. ;
  546. ; Parameters:
  547. ;    BX    -> strstack descriptor
  548. ;    SI    -> string
  549. ;    CX    == length of string (< 256)
  550. ;
  551. ; Returns:
  552. ;    AX    <- 0 if no errors
  553. ;          -1 if no room in stack
  554. ;          +1 if no word in string
  555. ;    SI    -> char after first word (or end-of-string)
  556. ;    CX    <- num remaining characters
  557. ;
  558. ; Register(s) destroyed:
  559. ;    DX
  560. ;-
  561. push_word proc    near
  562. ; Skip forward to first word
  563.     call    near ptr skip_whitespace    ;Returns
  564. ;                         SI->start of word
  565. ;                         CX<-remaining chars
  566.     jcxz    @push_word_98            ;No words in line
  567.     mov    dx,si                ;DX->start of word
  568.     push    cx                ;Save count
  569.     call    near ptr skip_nonwhite        ;Find end of word
  570. ;                         SI->beyond word
  571. ;                         CX<-remaining chars
  572.     pop    ax
  573.     sub    ax,cx                ;AX<-length of word
  574.     push    cx                ;Save remaining char count
  575.     xor    cx,cx                ;CX<-0 (don't force push)
  576.     call    near ptr strstk_push        ;Store macro name into
  577. ;                         macro stack. Params
  578. ;                         AX,BX,CX,DX
  579. ;                         Returns Cf = 0 or 1
  580.     pop    cx                ;CX<-remaining character
  581. ;    Assume no error
  582.     mov    ax,0    ;DON'T DO xor ax,ax SINCE CF to be preserved
  583.     jnc    @push_word_99            ;Jump if no error
  584.     dec    ax                ;Error AX <- -1
  585.     jmp    short @push_word_99        ;Exit
  586.  
  587. @push_word_98:
  588. ; No words found in line. Set return codes.
  589.     mov    ax,1                ;Code for blank line
  590.  
  591. @push_word_99:
  592.     ret
  593. push_word    endp
  594.  
  595.  
  596.  
  597.  
  598.  
  599. ;+
  600. ; FUNCTION : push_string
  601. ;
  602. ;    Pushed the specified string onto the specified stack.
  603. ;
  604. ; Parameters:
  605. ;    BX    -> strstack descriptor
  606. ;    SI    -> string
  607. ;    CX    == length of string must be < 256
  608. ;
  609. ; Returns:
  610. ;    CF    <- 0 if no errors
  611. ;           1 if no room in stack
  612. ;
  613. ; Register(s) destroyed:
  614. ;    AX,CX,DX
  615. ;-
  616. push_string proc    near
  617.     mov    dx,si                ;DX->start of string
  618.     mov    ax,cx                ;AX<-length of string
  619.     xor    cx,cx                ;CX<-0 (don't force push)
  620.     call    near ptr strstk_push        ;Store macro name into
  621. ;                         macro stack. Params
  622. ;                         AX,BX,CX,DX
  623. ;                         Returns Cf = 0 or 1
  624.     ret
  625. push_string    endp
  626.  
  627.  
  628.  
  629. ;+
  630. ; FUNCTION : bell
  631. ;
  632. ;    Called to ring the bell.
  633. ;
  634. ; Parameters:
  635. ;    None.
  636. ;
  637. ; Returns:
  638. ;    Nothing.
  639. ; Register(s) destroyed:
  640. ;    AX
  641. ;-
  642. bell    proc    near
  643.     cmp    silent,1
  644.     je    @bell_99
  645.     @DispCh    BEL
  646. @bell_99:
  647.     ret
  648. bell    endp
  649.  
  650.  
  651. ;+
  652. ; FUNCTION : output_counted_string
  653. ;
  654. ; Parameters :
  655. ;    CX - Number of bytes to display
  656. ;    DX - address of string
  657. ; Registers destroyed:
  658. ;    AX,BX,CX,DX
  659. output_counted_string proc near
  660.     mov    ah,40h
  661.     mov    bx,1                ;stdout handle
  662.     int    21h                ;Params ax,bx,cx,dx
  663.     ret
  664. output_counted_string endp
  665.  
  666. ;+
  667. ; FUNCTION: output_newline
  668. ;
  669. ; Registers destroyed:
  670. ;    AX,BX,CX,DX
  671. ;-
  672. output_newline proc near
  673.     @DispCh    CR
  674.     @DispCh    LF
  675.     ret
  676. output_newline endp
  677.  
  678.  
  679. ;+
  680. ; FUNCTION: dosify_line by wd
  681. ;
  682. ; Parameters:
  683. ;    SI -> string to massage
  684. ;    CX =  line length
  685. ; Registers destroyed:
  686. ;    AX,BX,CX,DX
  687. ;-
  688. dosify_line proc near
  689.     jcxz    @dosify_line_99
  690.     push    cx
  691.     push    si
  692. @dosify_line_10:
  693.     lodsb                ;al = currentchar
  694.     cmp    al,'/'            ;is this a slash?
  695.     je    @dosify_line_20        ;yes, change it
  696.     cmp    al,'\'            ;is this a backslash?
  697.     je    @dosify_line_25        ;yes, check it
  698.     cmp    al,'-'            ;is this a dash
  699.     jne    @dosify_line_40        ;no, leave it alone
  700.  
  701.     cmp    byte ptr [si-2],' '    ;is lastchar a space?
  702.     jne    @dosify_line_40        ;no, leave it alone
  703.     mov    al,'/'            ;yes, change " -" to " /"
  704.     jmp    short @dosify_line_30
  705. @dosify_line_20:
  706.     mov    al,'\'            ;change '/' to '\'
  707. @dosify_line_25:            ;see if this is a trailing slash
  708.     cmp    cl,1            ;is it at the end of the line?
  709.     je    @dosify_line_27        ;yes, drop it
  710.     cmp    byte ptr [si],' '    ;is it before a space?
  711.     jne    @dosify_line_30        ;no, leave it alone
  712. @dosify_line_27:
  713.     mov    al,' '            ;change trailing slash to a space
  714. @dosify_line_30:
  715.     mov    [si-1],al        ;store the revised character
  716. @dosify_line_40:
  717.     loop    @dosify_line_10
  718.     pop    si
  719.     pop    cx
  720. @dosify_line_99:
  721.     ret
  722. dosify_line endp
  723.  
  724.  
  725. CSEG    ENDS
  726.  
  727.     END
  728.  
  729.